﻿using Newtonsoft.Json;
using RestSharp;
using SUNRPA.CONTROLS.IMPL.domain;
using System.Runtime.InteropServices;
/// <summary>
/// based on restsharp
/// </summary>
namespace SUNRPA.CONTROLS.IMPL.util {
    public class HttpUtil :IDisposable {
        private static HttpUtil? httpUtil = null;
        private RestClient? client;
        public static JsonSerializerSettings setttings = new JsonSerializerSettings() { 
            TypeNameHandling = TypeNameHandling.Auto,
            NullValueHandling = NullValueHandling.Ignore,
        };
        private HttpUtil(string baseUrl) { 
            client = new RestClient(new RestClientOptions {
                BaseUrl = new Uri(baseUrl),
                MaxTimeout = 50000
            });
        }
         
        ~HttpUtil(){
            try { 
                client.Dispose();
                client = null;
            }catch(Exception){ 
            }
        }

        public static HttpUtil getInstance(string baseUrl) {
            lock(typeof(HttpUtil)) {
                if(httpUtil == null) { 
                    httpUtil = new HttpUtil(baseUrl);
                } else if(!httpUtil.client.Options.BaseUrl.ToString().Equals(baseUrl)){
                    httpUtil = new HttpUtil(baseUrl);
                }
                return httpUtil;
            } 
        }
        private HttpResponse<T>? OperResponse<T>(RestResponse res) {
            if(!res.IsSuccessful) { 
                throw new RpaRuntimeException($"网络请求出错，错误原因{res.ErrorException}");
            } else { 
                return JsonConvert.DeserializeObject<HttpResponse<T>>(res.Content, setttings);
            }
        }

        public HttpResponse<T>? SendGet<T>(string uri) { 
            RestRequest request = new RestRequest(uri, Method.Get);
            RestResponse res = client.ExecuteGet(request);
            return OperResponse<T>(res);
        }

        public HttpResponse<T>? SendGet<T>(string uri, Dictionary<string, string> getParam) { 
            RestRequest request = new RestRequest(uri, Method.Get);
            foreach(string key in getParam.Keys) { 
                request.AddParameter(key, getParam[key]);            
            }
            RestResponse res = client.ExecuteGet(request);
            return OperResponse<T>(res);
        }

        public HttpResponse<T>? SendPost<T>(string uri, object paramObj) {
            string objJson = JsonConvert.SerializeObject(paramObj, setttings);
            return SendPost<T>(uri, objJson);
        }

        public HttpResponse<T>? SendPost<T>(string uri, string paramJson) {
            RestRequest req = new RestRequest(uri, Method.Post);
            req.AddHeader("Content-Type", "application/json;charset=utf-8");
            req.AddParameter("application/json", paramJson, ParameterType.RequestBody);
            RestResponse res = client.ExecutePost(req);
            return OperResponse<T>(res);
        }

        public HttpResponse<T> UploadFile<T>(string uri, [Optional]string fileName, [Optional]string filePath, [Optional] byte[] fileBytes, [Optional] Dictionary<string, string> exterParam) { 
            RestRequest req = new RestRequest(uri, Method.Post);
            req.AddHeader("Content-Type", "multipart/form-data;charset=utf-8");
            if(!string.IsNullOrEmpty(filePath)) { 
                req.AddFile("upFile", filePath);
            } else { 
                req.AddFile("upFile", fileBytes, fileName);
            }
            if(exterParam != null) {
                foreach(string key in exterParam.Keys) { 
                    req.AddParameter(key, exterParam[key], ParameterType.RequestBody);
                }
            }
            RestResponse res = client.ExecutePost(req);
            return OperResponse<T>(res);
        }

        public byte[] DownLoadFile(string uri, Dictionary<string, string> getParam, [Optional] string savePath) { 
            RestRequest req = new RestRequest(uri, Method.Get);
            req.AddHeader("Cache-Control", "no-cache");
            if(getParam != null) { 
                foreach(string key in getParam.Keys) { 
                    req.AddParameter(key, getParam[key]);            
                }
            }
            byte[] bytes = client.DownloadData(req);
            if(!string.IsNullOrEmpty(savePath)) { 
                File.WriteAllBytes(savePath, bytes);
            }
            return bytes;
        }

        public Task<byte[]?> DownLoadFileAsync(string uri, Dictionary<string, string> getParam) { 
            RestRequest req = new RestRequest(uri, Method.Get);
            req.AddHeader("Cache-Control", "no-cache");
            if(getParam != null) { 
                foreach(string key in getParam.Keys) { 
                    req.AddParameter(key, getParam[key]);            
                }
            }
            Task<byte[]?> task = client.DownloadDataAsync(req);
            return task;
        }

        public Stream GetDownloadStream(string uri, Dictionary<string, string> getParam) { 
            RestRequest req = new RestRequest(uri, Method.Get);
            req.AddHeader("Cache-Control", "no-cache");
            if(getParam != null) { 
                foreach(string key in getParam.Keys) { 
                    req.AddParameter(key, getParam[key]);            
                }
            }
            return client.DownloadStream(req);
        }

        public void Dispose() {
            if(client != null) { 
                client.Dispose();
                client = null;
            }
        }
    }
}
